const { app, BrowserWindow, ipcMain } = require("electron");
const WebSocket = require("ws");
const http = require("http");
const path = require("path");
const fs = require("fs");
const puppeteer = require("puppeteer");
const winston = require("winston");
const moment = require("moment-timezone");
const {
  operateNode,
  swipe,
  getText,
  getAllFiles,
  uploadFilesByXPath,
  getChildPath,
  uploadFilesBySelector,
  buildXPathForText,
  splitString,
  checkExpiration,
  Page_status_window,
} = require("./methods");
// 设置日志存储目录和文件
const logDir = path.resolve(process.cwd(), "logs");
if (!fs.existsSync(logDir)) {
  fs.mkdirSync(logDir);
}

const logFilePath = path.resolve(logDir, "app.log");
// 配置 winston 日志记录器
const logger = winston.createLogger({
  level: "info", // 设置最低日志级别为 info
  format: winston.format.combine(
    winston.format.timestamp({
      format: () => moment().tz("Asia/Shanghai").format("YYYY-MM-DD HH:mm:ss"), // 设置时间为中国时间
    }),
    winston.format.simple()
  ),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: logFilePath }),
  ],
});
const getFilesInDirectory = (dirPath) => {
  return fs
    .readdirSync(dirPath)
    .filter((file) => fs.statSync(path.join(dirPath, file)).isFile());
};
// 将文件移动到另一个文件夹
const moveFile = (srcPath, destDir) => {
  // 检查目标文件夹是否存在，不存在则创建
  if (!fs.existsSync(destDir)) {
    fs.mkdirSync(destDir, { recursive: true }); // { recursive: true } 允许创建多层文件夹
    console.log(`目标文件夹不存在，已创建: ${destDir}`);
  }

  const destPath = path.join(destDir, path.basename(srcPath));
  fs.renameSync(srcPath, destPath); // 将文件从源路径移动到目标文件夹
  console.log(`文件已移动: ${srcPath} -> ${destPath}`);
};
let win; // 渲染进程的窗口对象
let clients = []; // 存储连接的客户端信息

// 创建 HTTP 服务器
const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/plain" });
  res.end("Hello from WebSocket server");
});

// 创建 WebSocket 服务器并挂载到 HTTP 服务器上
const wss = new WebSocket.Server({ noServer: true });

// 处理 WebSocket 连接
wss.on("connection", (ws, request) => {
  // 从 URL 查询参数中提取客户端 ID
  const urlParams = new URLSearchParams(request.url.split("?")[1]);
  const clientId = urlParams.get("id") || `Client-${Date.now()}`; // 如果没有提供 id，则使用当前时间戳作为默认 ID

  // 保存客户端信息
  clients.push({ id: clientId, ws });

  // 向渲染进程发送客户端连接成功的消息
  win.webContents.send("client-connected", { clientId });
  logger.info("连接建立:", clientId);
  // 监听客户端发送的消息
  ws.on("message", (message) => {
    console.log(`Received message from ${clientId}: ${message}`);
    win.webContents.send("client-message", { clientId, message });
  });

  // 监听客户端关闭连接
  ws.on("close", () => {
    console.log(`${clientId} disconnected`);
    // 移除已断开的客户端
    clients = clients.filter((client) => client.id !== clientId);
    win.webContents.send("client-disconnected", { clientId });
  });
});

// 在 HTTP 服务器上监听 WebSocket 升级请求
server.on("upgrade", (request, socket, head) => {
  wss.handleUpgrade(request, socket, head, (ws) => {
    wss.emit("connection", ws, request);
  });
});

// 启动 WebSocket 服务器
server.listen(3001, "0.0.0.0", () => {
  console.log("WebSocket server is listening on ws://0.0.0.0:3001");
});

// 创建 BrowserWindow
function createWindow() {
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
    },
  });

  win.loadFile("index.html"); // 加载本地 HTML 文件
}

// 启动应用
app.whenReady().then(() => {
  createWindow();
  logger.info("程序启动");
});

// 在所有窗口关闭时退出应用
app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});
const dataUriToBase64 = (dataUri) => {
  const matches = dataUri.match(/^data:(.+?);base64,(.+)$/);
  if (matches && matches.length === 3) {
    return matches[2]; // 返回纯 base64 数据
  }
  throw new Error("Invalid data URI");
};
// 定时发布视频
async function scheduleVideoPost(
  page,
  sourceDir,
  destDir,
  targetTime,
  description,
  address
) {
  console.log("时间", targetTime);
  await page.goto("https://channels.weixin.qq.com/platform", {
    waitUntil: "networkidle0", // 确保页面加载完成
  });
  const files = getFilesInDirectory(sourceDir);
  console.log(`准备上传的文件: ${files.join(", ")}`);
  if (files.length === 0) {
    console.log("没有文件可上传，结束操作。");
    return false; // 结束当前函数，或者使用 `process.exit()` 来退出整个脚本
  }
  // 点击发表视频
  await operateNode(
    page,
    '//*[@id="container-wrap"]/div[2]/div/div[2]/div[3]/div[1]/div/div[1]/div[2]/div/button'
  );

  // 上传视频
  const filename = files[0];
  const filePath = path.posix.join(sourceDir, files[0]);
  const finalFilePath = `./${filePath}`;
  await uploadFilesBySelector(page, 'input[type="file"]', finalFilePath);
  console.log(`文件已上传: ${finalFilePath}`);

  // 等待上传完成
  await page.waitForFunction(() => {
    const element = document.querySelector(".tag-inner");
    return element && element.textContent.trim() === "删除";
  });

  // 上传完成后将文件移动到目标文件夹
  moveFile(filePath, destDir);

  //点开地址
  await operateNode(page, 'div[class="position-display-wrap"]');
  if (address) {
    //输入地址
    await operateNode(
      page,
      'input[placeholder="搜索附近位置"]',
      "输入",
      address
    );
    await page.evaluate(() => {
      // 获取所有的 .option-item 元素
      const items = document.querySelectorAll(
        ".common-option-list-wrap .option-item"
      );

      // 遍历这些选项，找到第一个不包含 "不显示位置" 的元素并点击
      for (let item of items) {
        const name = item.querySelector(
          ".location-item-info .name"
        ).textContent;
        if (name !== "不显示位置") {
          item.click();
          break;
        }
      }
    });
  } else {
    //点击不显示位置
    await operateNode(page, await buildXPathForText(page, "不显示位置"));
  }

  //输入描述
  await operateNode(
    page,
    'div[data-placeholder="添加描述"]',
    "输入",
    description
  );
  // 设置定时发布
  await operateNode(page, await buildXPathForText(page, "定时"));
  await operateNode(page, 'input[placeholder="请选择发表时间"]');

  // 设置目标时间（年月日时分）
  let [targetYear, targetMonth, targetDate, targetHour, targetMinute] =
    targetTime.split("-");
  await sleep(1000);
  console.log(
    "时间",
    targetYear,
    targetMonth,
    targetDate,
    targetHour,
    targetMinute
  );
  // 选择年份
  await page.click(".weui-desktop-picker__panel__hd span:nth-child(2)");
  const yearElements = await page.$$(
    ".weui-desktop-picker__panel__bd .weui-desktop-picker__table-row a"
  );
  for (let yearElement of yearElements) {
    const yearText = await page.evaluate(
      (el) => el.textContent.trim(),
      yearElement
    );
    const isDisabled = await page.evaluate(
      (el) => el.classList.contains("weui-desktop-picker__disabled"),
      yearElement
    );

    if (isDisabled) continue;
    if (yearText === targetYear) {
      await yearElement.click();
      console.log(`点击年份: ${yearText}`);
      break;
    }
  }
  await sleep(1000);
  // 选择月份
  const monthElements = await page.$$(
    ".weui-desktop-picker__panel__bd .weui-desktop-picker__table-row a"
  );
  for (let monthElement of monthElements) {
    const monthText = await page.evaluate(
      (el) => el.textContent.trim(),
      monthElement
    );
    const isDisabled = await page.evaluate(
      (el) => el.classList.contains("weui-desktop-picker__disabled"),
      monthElement
    );
    if (isDisabled) continue;
    if (monthText === targetMonth) {
      await monthElement.click();
      console.log(`点击月份: ${monthText}`);
      break;
    }
  }
  await sleep(1000);
  // 选择日期
  const dateElements = await page.$$(`${".weui-desktop-picker__table-row a"}`);
  for (let dateElement of dateElements) {
    const dateText = await page.evaluate(
      (el) => el.textContent.trim(),
      dateElement
    );
    const isDisabled = await page.evaluate(
      (el) => el.classList.contains("weui-desktop-picker__disabled"),
      dateElement
    );

    if (isDisabled) continue;
    if (dateText === targetDate) {
      await dateElement.click();
      console.log(`点击日期: ${dateText}`);
      break;
    }
  }
  await sleep(1000);
  // 选择小时和分钟
  await page.click('input[placeholder="请选择时间"]');
  await page.waitForSelector(".weui-desktop-picker__time__hour");
  await page.waitForSelector(".weui-desktop-picker__time__minute");

  // 选择小时
  targetHour = targetHour.padStart(2, "0");
  const hours = await page.$$(
    `ol.weui-desktop-picker__time__hour li:not(.weui-desktop-picker__disabled)`
  );
  for (let hour of hours) {
    const hourText = await page.evaluate((el) => el.textContent.trim(), hour);
    console.log(`检查小时: ${hourText}`);
    if (hourText === targetHour) {
      await hour.click();
      console.log(`选择小时: ${hourText}`);
      break;
    }
  }

  // 选择分钟
  targetMinute = targetMinute.padStart(2, "0");
  const minutes = await page.$$(
    `ol.weui-desktop-picker__time__minute li:not(.weui-desktop-picker__disabled)`
  );

  for (let minute of minutes) {
    const minuteText = await page.evaluate(
      (el) => el.textContent.trim(),
      minute
    );
    console.log(`检查分钟: ${minuteText}`);
    if (minuteText === targetMinute) {
      await minute.click();
      console.log(`选择分钟: ${minuteText}`);
      break;
    }
  }
  await sleep(3000);

  await operateNode(page, await buildXPathForText(page, "发表时间"));
  // 点击发布
  console.log("点击发布");
  // await operateNode(page, await buildXPathForText(page, "发表"));
  const buttons = await page.$$(".weui-desktop-btn.weui-desktop-btn_primary");

  // 遍历所有按钮并根据按钮文本进行选择
  for (let button of buttons) {
    const text = await page.evaluate((el) => el.textContent.trim(), button);

    // 检查文本是否符合你要点击的文本（例如：'发表'）
    if (text === "发表") {
      await button.click(); // 点击该按钮
      break; // 找到后跳出循环
    }
  }
  console.log("视频已发布");
  await sleep(5000);
  return true;
}
// 私信
async function massage_sent(page, massage) {
  await page.goto("https://channels.weixin.qq.com/platform", {
    waitUntil: "networkidle0", // 确保页面加载完成
  });

  // 操作 '互动管理' 和 '私信' 的链接
  await operateNode(page, await buildXPathForText(page, "互动管理"));
  await operateNode(page, await buildXPathForText(page, "私信"));

  await sleep(5000); // 等待页面加载

  // 获取所有 iframe 元素
  const frameHandles = await page.$$("iframe");
  if (frameHandles && frameHandles.length > 0) {
    const frame = await frameHandles[0].contentFrame();

    // 在 iframe 中滚动类名为 scroll-list 的容器
    await frame.evaluate(() => {
      const greetingMessageElement = Array.from(
        document.querySelectorAll("a")
      ).find((el) => el.textContent.includes("打招呼消息"));
      if (greetingMessageElement) {
        greetingMessageElement.click();
      } else {
        console.log("没有找到“打招呼消息”链接");
      }
      const scrollList = document.querySelector(".scroll-list");
      if (scrollList) {
        scrollList.scrollTop = scrollList.scrollHeight; // 滚动到容器底部
      }
    });

    // 等待滚动效果完成（可以根据页面的具体情况调整延时）
    await sleep(3000);

    // 在 iframe 中操作元素并点击所有符合条件的元素
    await frame.evaluate(async (massage) => {
      // 将 massage 按空格拆分成数组
      const massageArray = massage.split(" ");

      const elements = document.querySelectorAll(".session-wrap");
      console.log("elements", elements);

      for (let element of elements) {
        try {
          // 随机选择一个消息
          const randomMassage =
            massageArray[Math.floor(Math.random() * massageArray.length)];

          console.log("随机选择的消息：", randomMassage);
          // 点击每个元素
          element.click();
          // 等待页面更新的时间，确保点击后页面响应
          await new Promise((resolve) => setTimeout(resolve, 1000)); // 1秒钟等待，可以根据实际情况调整时间

          // 查找textarea并输入内容
          const textarea = document.querySelector(".edit_area");
          if (textarea) {
            // 聚焦到textarea
            textarea.focus();

            // 清空textarea的内容（如果需要的话）
            textarea.value = "";
            console.log("massage", randomMassage);
            // 输入消息
            textarea.value = randomMassage; // 直接赋值到textarea中

            // 触发输入事件（模拟用户输入）
            const event = new Event("input", { bubbles: true });
            textarea.dispatchEvent(event);

            // 等待输入完成，确保内容已被输入
            await new Promise((resolve) => setTimeout(resolve, 500)); // 可以根据需要调整时间
          } else {
            console.error("没有找到textarea 元素");
          }

          // 查找并点击按钮
          const button = document.querySelector(
            ".weui-desktop-btn.weui-desktop-btn_default"
          );
          if (button) {
            button.click();
          } else {
            console.error("没有找到按钮元素");
          }
        } catch (err) {
          console.error(`处理元素时发生错误: ${err}`);
        }
      }
    }, massage);
  } else {
    console.log("没有足够的 iframe 元素");
  }

  return true;
}

async function getqrcode(page) {
  // 等待 iframe 加载
  const iframeElement = await page.waitForSelector("iframe.display"); // 找到 iframe 元素
  const iframe = await iframeElement.contentFrame(); // 获取 iframe 的 Frame 对象

  // 等待二维码图片加载
  await iframe.waitForSelector(".qrcode", { visible: true, timeout: 10000 });

  // 获取二维码图片的 URL (这里直接是 Base64 数据)
  const qrCodeSrc = await iframe.$eval(".qrcode", (img) => img.src);

  // 从数据 URL 中提取 Base64 部分
  const base64Data = qrCodeSrc.split(",")[1]; // 去掉前面的 'data:image/png;base64,' 部分

  // // 将图片数据保存到本地文件
  // const buffer = Buffer.from(base64Data, 'base64');
  // fs.writeFile("qrCodeImage.png", buffer, (err) => {
  //     if (err) {
  //         console.error("保存图片失败:", err);
  //     } else {
  //         console.log("图片保存成功！");
  //     }
  // });

  // 返回 Base64 数据 (如果需要的话)
  return base64Data;
}

// 用于生成随机时间的函数
function getRandomTimeInRange(start, end) {
  const diff = end - start;
  const randomOffset = Math.floor(Math.random() * diff);
  return new Date(start.getTime() + randomOffset);
}

// 格式化日期为 "YYYY-M-D-H-m" 格式（不加前导零）
function formatDateToString(date) {
  const year = date.getFullYear();
  const month = date.getMonth() + 1; // 月份是从 0 开始的
  const day = date.getDate();
  const hours = date.getHours();
  const minutes = date.getMinutes();
  return `${year}-${month}-${day}-${hours}-${minutes}`;
}
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// 监听渲染进程请求开始任务
ipcMain.on("start-task", async (event, { clientId, taskDetails }) => {
  logger.info(
    `任务开始:${clientId},任务参数:${JSON.stringify(taskDetails, null, 2)}`
  );
  const client = clients.find((client) => client.id === clientId);
  event.sender.send(`task-status-${clientId}`, "任务开始");

  const browserPath = path.resolve(process.cwd(), "chrome-win64/chrome.exe");
  const userDataDir = path.resolve(process.cwd(), `user_data_${0}`);
  const date = taskDetails.date;
  const startTime = taskDetails.startTime;
  const endTime = taskDetails.endTime;
  const startDate = new Date(`${date}T${startTime}:00`);
  const endDate = new Date(`${date}T${endTime}:00`);
  const folder = taskDetails.folder;
  const description = taskDetails.description;
  const address = taskDetails.address;
  const quantity = taskDetails.quantity;
  const interval = Number(taskDetails.interval);
  let responseData;

  let browser; // 用于存储浏览器实例

  try {
    // 启动浏览器
    while (true) {
      browser = await puppeteer.launch({
        headless: false, // 显示浏览器窗口
        executablePath: browserPath, // 使用指定的 Chrome 浏览器路径
        args: ["--no-sandbox", "--disable-setuid-sandbox"],
        defaultViewport: { width: 1980, height: 900 },
      });
      const page = await browser.newPage();

      if (client && client.ws) {
        // 向手机发送二维码和登录请求
        try {
          while (true) {
            logger.info(`${clientId}:尝试登录`);
            //进入网页，获取二维码,发送给手机
            await page.goto("https://channels.weixin.qq.com/platform", {
              waitUntil: "networkidle0", // 确保页面加载完成
            });
            const img_base64 = await getqrcode(page);
            const message = JSON.stringify({
              type: "start-task",
              base64: img_base64,
            });
            client.ws.send(message);
            console.log(`Sent task start message to ${clientId}:`, taskDetails);
            //等待手机回复，如果请求二维码则进入下一个循环，重新获取二维码发送。如果成功登录则break出去，执行发视频操作。
            //如果手机回复号用完了则结束任务
            const response = await new Promise((resolve, reject) => {
              client.ws.once("message", (msg) => {
                resolve(msg); // 当收到消息时，返回响应
              });

              // 如果需要处理超时，可以添加超时逻辑
              setTimeout(
                () =>
                  reject(
                    new Error(
                      `Timeout waiting for message from client ${clientId}`
                    )
                  ),
                600000
              );
            });

            // 假设客户端返回的是 JSON 格式的消息
            responseData = JSON.parse(response);

            // 根据响应执行后续任务
            if (
              responseData.type === "task-status" &&
              responseData.status === "completed"
            ) {
              logger.info(`${clientId}:登录成功;${responseData["message"]}`);
              break;
            } else if (
              responseData.type === "task-status" &&
              responseData.status === "retry"
            ) {
              logger.info(
                `${clientId}:尝试再次登录;${responseData["message"]}`
              );
              continue;
            } else if (
              responseData.type === "task-status" &&
              responseData.status === "end"
            ) {
              event.sender.send(
                `task-status-${clientId}`,
                "账号用完,任务完成",
                responseData["message"]
              );
              logger.info(`${clientId}:账号用完;`);
              return;
            } else {
              event.sender.send(`task-status-${clientId}`, "收到异常数据");
              logger.info(`${clientId}:收到异常数据，自动结束;${responseData}`);
              return;
            }
          }

          event.sender.send(`task-status-${clientId}`, "任务执行中");
          console.log("开始与结束时间", startDate, endDate);
          // 获取随机时间
          let randomTime = getRandomTimeInRange(startDate, endDate);
          console.log("随机时间", randomTime);
          // 格式化随机时间为 "YYYY-M-D-H-m" 格式（不加前导零）
          let formattedRandomTime = formatDateToString(randomTime);
          console.log("格式化随机时间", formattedRandomTime);

          // 执行发送视频，发送私信操作 interval
          let file_if = false;
          let dateObj = new Date(randomTime);
          for (let i = 0; i < quantity; i++) {
            // 每次循环时，将 formattedRandomTime 转换为 Date 对象
            formattedRandomTime = formatDateToString(dateObj);
            console.log("本次时间", formattedRandomTime);
            // 执行发送视频操作
            file_if = await scheduleVideoPost(
              page,
              `./video/${folder}`,
              `./used/${folder}`,
              formattedRandomTime,
              description,
              address
            );

            if (file_if) {
              logger.info(
                `${clientId},${responseData["message"]}: 视频${i + 1} 上传成功`
              );
            }
            dateObj.setMinutes(dateObj.getMinutes() + interval);
            // 更新 randomTime 为当前的时间，用于下一次循环
            randomTime = dateObj;
            sleep(3000);
          }

          // 私信
          if (await massage_sent(page, taskDetails.message)) {
            logger.info(`${clientId},${responseData["message"]}:私信发送完毕`);
          }

          // 任务执行完后关闭浏览器
          if (!file_if) {
            event.sender.send(
              `task-status-${clientId},${responseData["message"]}`,
              "视频用完，任务完成"
            );
            logger.info(
              `${clientId},${responseData["message"]}:视频用完，任务自动结束;`
            );
            return;
          }
        } catch (error) {
          logger.error(
            `Error during task execution for client ${clientId}:`,
            error
          );
        } finally {
          // 确保浏览器关闭
          if (browser) {
            try {
              await browser.close();
              logger.info(`${clientId}: 浏览器已关闭`);
            } catch (error) {
              logger.error(`${clientId}: 关闭浏览器时出错`, error);
            }
          }
        }
      } else {
        event.sender.send(
          `task-status-${clientId}`,
          "连接断开，任务自动结束",
          responseData["message"]
        );
        logger.error(
          `${clientId}:连接断开，任务自动结束;`,
          responseData["message"]
        );
        return;
      }
    }
  } finally {
    // 确保浏览器关闭
    if (browser) {
      try {
        await browser.close();
        logger.info(`${clientId}: 浏览器已关闭`);
      } catch (error) {
        logger.error(`${clientId}: 关闭浏览器时出错`, error);
      }
    }
    event.sender.send(
      `task-status-${clientId}`,
      "任务结束",
      responseData ? responseData["message"] : "任务完成"
    );
    logger.info(`任务结束:${clientId}`);
  }
});

// 监听渲染进程接收到客户端的消息并进行任务中的处理
ipcMain.on("receive-client-response", (event, { clientId, response }) => {
  const client = clients.find((client) => client.id === clientId);
  if (client && client.ws) {
    // 在接收到客户端的响应后进行处理
    console.log(`Received response from ${clientId}:`, response);
    // 你可以在这里继续处理响应
  }
});
